using System;
using System.Collections.Generic;
using System.Text;
using OOFluidFramework.Orders;
using OOFluidFramework;
using OOFluidFramework.Utility;

namespace OOFluidFramework.Operators
{
    class FluidOperatorImpl : FluidOperator
    {
        protected Vector2 lo;
        protected Vector2 prelo;
               
        protected double timeStep;
        protected FluidSpaceOperatorRefere spaceRefere;

        protected Vector2 val;
        protected Vector2 preval;
        
        protected double weightCount;
        protected bool isInterpolated;
        protected double preWeightCount;

        protected bool enabled;


        public FluidOperatorImpl(Vector2 InitialLocation, FluidSpaceOperatorRefere spaceRefere)
        {
            this.Location = InitialLocation;
            this.spaceRefere = spaceRefere;
            timeStep = spaceRefere.RetrieveTimeStep();
            isInterpolated = false;
            weightCount = 0;
        }

        public Vector2 Location
        {
            get { return new Vector2(lo); }
            set { prelo = lo; lo = value; }
        }
        public Vector2 preLocation
        {
            get { return new Vector2(prelo); }
        }
        public Vector2 Value
        {
            get { return new Vector2(val); }
            set { preval = val; val = value; }
        }
        public Vector2 preValue
        {
            get { return new Vector2(preval); }
        }
        public bool Enabled
        {
            get { return enabled; }
            set { enabled = value; }
        }
        public double ReportDistanceP2(FluidOperator op)
        {
            Vector2 opLocation = op.ReportLocation();
            ReportDistanceP2(opLocation);
        }
        public double ReportDistanceP2(Vector2 Location)
        {            
            return (Location.x - lo.x) * (Location.x - lo.x)
                    + (Location.y - lo.y) * (Location.y - lo.y);
        }
        public double Receive(Vector2 thisValue, FluidOperator op, Interpolation inpol)
        {
            double Weight = inpol.ReportWeight(this, op);
            val += thisValue * Weight;
            weightCount += Weight;
            isInterpolated = true;
            return Weight;
        }
        public double Receive(Vector2 thisValue, double Reference, Interpolation inpol)
        {
            double Weight = inpol.ReportWeight(Reference);
            val += thisValue * Weight;
            weightCount += Weight;
            isInterpolated = true;
            return Weight;
        }
        public Vector2 NormalizeSpeed()
        {
            if (!isInterpolated) return new Vector2(val);
            val = val / weightCount;
            preWeightCount = weightCount;
            weightCount = 0.0;
            isInterpolated = false;
            return new Vector2(val);
        }
    }

    interface FluidOperator
    {
        Vector2 Location
        {
            get;
            set;
        }
        Vector2 preLocation
        {
            get;
        }
        Vector2 Value
        {
            get;
            set;
        }
        Vector2 preValue
        {
            get;
        }
        bool Enabled
        {
            get;
            set;
        }
        double ReportDistanceP2(FluidOperator op);
        double ReportDistanceP2(Vector2 Location);
        double Receive(Vector2 thisValue, FluidOperator op, Interpolation inpol);
        double Receive(Vector2 thisValue, double Reference, Interpolation inpol);
        Vector2 NormalizeSpeed();
    }
}
